package mallgoods

import (
	"context"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/jwt"

	// "mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/product/rpc/productclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type GetGoodsDetailLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetGoodsDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetGoodsDetailLogic {
	return &GetGoodsDetailLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetGoodsDetailLogic) GetGoodsDetail(
	req *types.GetGoodsDetailReq,
	headers *[]*types.Header,
) (resp *types.GoodsDetailInfo, err error) {
	if req.Id == nil || *req.Id == 0 {
		// return nil, resultx.NewErrCode(resultx.PRODUCT_ID_REQUIRED)
		return &types.GoodsDetailInfo{}, nil
	}

	userId := jwt.GetUserId(l.ctx)

	preload := "product:Id,ParentId,Title,Slug,Excerpt,Status" // Status必须
	eagerLoad := "product:productDetail,productMedia,productRelationship,productTerm,productMeta,productAttribute,productVariation,productVariationMeta"
	preload += ";productDetail:Content,Tracing"
	preload += ";productMedia:Uid,Thumbnail,Order,Url,altText,metaData"
	preload += ";productRelationship:PerfumeId,PerfumeName,PerfumeSlug,BrandId,BrandName,BrandSlug"
	preload += ";productTerm:Id,Name,Slug,ParentId"
	preload += ";productMeta:mediaId,mediaUrl,retailPriceMin,scoreMin,hotSell,showStock,stock,stockUnit,gemPriceMin,gemPriceMax"
	preload += ";productAttribute:Id,IsSku,Name,Slug,HasImage"
	preload += ";productVariation:Id,RetailPrice"
	preload += ";productVariationMeta:stock,mediaId,mediaUrl,sku,skuKey"
	filters := []string{
		"virtual,equalTo:" + strconv.FormatInt(int64(globalkey.ProductTypePhysical), 10),
	}
	platformId := globalkey.ThirdPartyPlatformWechatMini

	var searchLogId *uint64
	if req.SearchId != nil && *req.SearchId > 0 {
		searchLogId = pointy.GetPointer(uint64(*req.SearchId))
	}

	res, err := l.svcCtx.ProductRpc.GetProductById(l.ctx, &productclient.BaseIdReq{
		Id:          req.Id,
		Preload:     pointy.GetPointer(preload),
		EagerLoad:   pointy.GetPointer(eagerLoad),
		Filter:      pointy.GetPointer(strings.Join(filters, ";")),
		VisitorId:   pointy.GetPointer(userId),
		PlatformId:  pointy.GetPointer(platformId),
		SearchLogId: searchLogId,
	})
	if err != nil {
		logx.Errorw("GetGoodsDetail GetProductById err", logx.Field("detail", err.Error()))
		// return nil, err
		return &types.GoodsDetailInfo{}, nil
	}

	if res == nil || res.Id == nil || *res.Id == 0 {
		// return nil, resultx.NewErrCode(resultx.PRODUCT_ID_INVALID)
		return &types.GoodsDetailInfo{}, nil
	}

	var categories []*types.CategoryInfo
	if len(res.Categories) > 0 {
		for _, v := range res.Categories {
			categories = append(categories, &types.CategoryInfo{
				Id:       v.Id,
				Name:     v.Name,
				Slug:     v.Slug,
				ParentId: v.ParentId,
			})
		}
	}
	var tags []*types.TagInfo
	if len(res.Tags) > 0 {
		for _, v := range res.Tags {
			tags = append(tags, &types.TagInfo{
				Id:   v.Id,
				Name: v.Name,
				Slug: v.Slug,
			})
		}
	}

	var selectPriceMin string
	var retailPriceMin *string
	// var scoreMin *uint32
	var showStock *bool
	var stock uint32
	var stockUnit *string
	var buyNumMax *uint32
	var buyNumber *uint32
	var isNew *bool
	var isHot *bool
	var mediaId *string
	var mediaUrl *string
	var gemPriceMin string
	var gemPriceMax string
	var meta []*types.MetaInfo
	if len(res.Meta) > 0 {
		for _, v := range res.Meta {
			if v.Key == nil || v.Value == nil {
				continue
			}

			val := *v.Value
			switch *v.Key {
			case "retailPriceMin":
				selectPriceMin = val
				retailPriceMin = pointy.GetPointer(val)
			// case "scoreMin":
			// 	if i, err := strconv.ParseInt(val, 10, 32); err == nil {
			// 		scoreMin = pointy.GetPointer(uint32(i))
			// 	}
			case "isNew":
				if val == "1" {
					isNew = pointy.GetPointer(true)
				}
			case "isHot":
				if val == "1" {
					isHot = pointy.GetPointer(true)
				}
			case "hotSell":
				if val == "1" {
					isHot = pointy.GetPointer(true)
				}
			case "mediaId":
				mediaId = v.Value
			case "mediaUrl":
				mediaUrl = v.Value
			case "stock":
				if i, err := strconv.ParseInt(val, 10, 32); err == nil {
					stock = uint32(i)
				}
			case "stockUnit":
				stockUnit = v.Value
			case "gemPriceMin":
				gemPriceMin = val
			case "gemPriceMax":
				gemPriceMax = val
			default:
				meta = append(meta, &types.MetaInfo{
					Id:    v.Id,
					Key:   v.Key,
					Value: v.Value,
				})
			}
		}

		if gemPriceMin != gemPriceMax { // Todo: 暂时限制，不允许试香有多个规格
			gemPriceMin = ""
		}
	}
	if stock > 0 {
		buyNumber = pointy.GetPointer(uint32(1))
		if stock > uint32(99) {
			buyNumMax = pointy.GetPointer(uint32(99))
		} else {
			buyNumMax = pointy.GetPointer(stock)
		}
	} else {
		buyNumber = pointy.GetPointer(uint32(0))
	}

	var brand *types.KbEntryInfo
	var perfume *types.KbEntryInfo
	if len(res.Relations) > 0 {
		for _, v := range res.Relations {
			if v.Key != nil {
				switch *v.Key {
				case globalkey.ProductRelationNameBrand:
					brand = &types.KbEntryInfo{
						Id:    v.Id,
						Title: v.Name,
						Slug:  v.Slug,
					}
				case globalkey.ProductRelationNamePerfume:
					perfume = &types.KbEntryInfo{
						Id:    v.Id,
						Title: v.Name,
						Slug:  v.Slug,
					}
				}
			}
		}
	}

	var photos []*types.MediaInfo
	if len(res.Media) > 0 {
		for _, v := range res.Media {
			var url string
			if v.Url != nil && len(*v.Url) > 0 {
				url = *v.Url
			}
			if len(url) == 0 && v.Uri != nil && len(*v.Uri) > 0 {
				url = *v.Uri
			}

			var thumbnail *bool
			if v.Thumbnail != nil {
				thumbnail = pointy.GetPointer(*v.Thumbnail > 0)
			}

			photos = append(photos, &types.MediaInfo{
				Uid:       v.Uid,
				Id:        v.Id,
				Thumbnail: thumbnail,
				Order:     v.Order,
				Url:       pointy.GetPointer(url),
				AltText:   v.AltText,
				MetaData:  v.MetaData,
			})

			if mediaUrl != nil {
				continue
			}

			mediaUrl = pointy.GetPointer(url)
		}
	} else if mediaUrl != nil {
		photos = append(photos, &types.MediaInfo{
			Id:        mediaId,
			Thumbnail: pointy.GetPointer(true),
			Order:     pointy.GetPointer(uint32(0)),
			Url:       mediaUrl,
		})
	}

	var attrs []*types.ProductAttrInfo
	if len(res.Attrs) > 0 {
		for _, v := range res.Attrs {
			if len(v.Options) > 0 {
				var options []*types.ProductAttrOptInfo
				for _, opt := range v.Options {
					options = append(options, &types.ProductAttrOptInfo{
						Id:       opt.Id,
						Label:    opt.Label,
						Slug:     opt.Slug,
						MediaId:  opt.MediaId,
						MediaUrl: opt.MediaUrl,
					})
				}
				var hasMedia *bool
				if v.HasMedia != nil && *v.HasMedia > 0 {
					hasMedia = pointy.GetPointer(true)
				}
				attrs = append(attrs, &types.ProductAttrInfo{
					Id:       v.Id,
					Label:    v.Label,
					Slug:     v.Slug,
					HasMedia: hasMedia,
					Options:  options,
				})
			}
		}
	}

	var specs []*types.ProductAttrInfo
	idSpecOptMap := make(map[string]*types.ProductAttrOptInfo)
	idSpecMap := make(map[string]*productclient.ProductAttrInfo)
	if len(res.Specs) > 0 {
		for _, v := range res.Specs {
			if len(v.Options) > 0 {
				var options []*types.ProductAttrOptInfo
				for _, opt := range v.Options {
					if opt.Id == nil {
						continue
					}

					optId := strconv.FormatInt(int64(*opt.Id), 10)
					option := &types.ProductAttrOptInfo{
						Id:       opt.Id,
						Label:    opt.Label,
						Slug:     opt.Slug,
						MediaId:  opt.MediaId,
						MediaUrl: opt.MediaUrl,
					}
					idSpecOptMap[optId] = option
					options = append(options, option)
					idSpecMap[optId] = v
				}
				var hasMedia *bool
				if v.HasMedia != nil && *v.HasMedia > 0 {
					hasMedia = pointy.GetPointer(true)
				}
				specs = append(specs, &types.ProductAttrInfo{
					Id:       v.Id,
					Label:    v.Label,
					Slug:     v.Slug,
					HasMedia: hasMedia,
					Options:  options,
				})
			}
		}
	}

	var skus []*types.ProductVariationInfo
	var hasMoreSelect *bool
	if len(res.Skus) > 0 {
		for _, v := range res.Skus {
			if v.Key == nil {
				continue
			}

			var optKeys []string
			var specs []*types.ProductAttrInfo
			if keys := strings.Split(*v.Key, ","); len(keys) > 0 {
				for _, optKey := range keys {
					if spec, ok := idSpecMap[optKey]; ok {
						if opt, ok := idSpecOptMap[optKey]; ok {
							optKey = "opt_" + optKey
							optKeys = append(optKeys, optKey)
							opt.Key = pointy.GetPointer(optKey)
							options := []*types.ProductAttrOptInfo{opt}
							var hasMedia *bool
							if spec.HasMedia != nil && *spec.HasMedia > 0 {
								hasMedia = pointy.GetPointer(true)
							}
							var specKey *string
							if spec.Id != nil {
								specKey = pointy.GetPointer("spec_" + strconv.FormatInt(int64(*spec.Id), 10))
							}
							specs = append(specs, &types.ProductAttrInfo{
								Id:       spec.Id,
								Key:      specKey,
								Label:    spec.Label,
								Slug:     spec.Slug,
								HasMedia: hasMedia,
								Options:  options,
							})
						}
					}
				}
			}
			var buyNumMax *uint32
			if v.Inventory != nil {
				if *v.Inventory > uint32(99) {
					buyNumMax = pointy.GetPointer(uint32(99))
				} else {
					buyNumMax = v.Inventory
				}
			}
			skus = append(skus, &types.ProductVariationInfo{
				Id:           v.Id,
				Key:          pointy.GetPointer(strings.Join(optKeys, "_-_")),
				RetailPrice:  v.RetailPrice,
				CounterPrice: v.CounterPrice,
				Inventory:    v.Inventory,
				Weight:       v.Weight,
				SaleCount:    v.SaleCount,
				// MediaId:      v.MediaId,
				BuyNumMax: buyNumMax,
				MediaUrl:  v.MediaUrl,
				Specs:     specs,
			})

			if hasMoreSelect != nil {
				continue
			}

			if v.RetailPrice != nil && len(*v.RetailPrice) > 0 && *v.RetailPrice != selectPriceMin {
				hasMoreSelect = pointy.GetPointer(true)
			}
		}
	}

	var preTag *string
	if isHot != nil && *isHot {
		preTag = pointy.GetPointer("热卖")
	} else if isNew != nil && *isNew {
		preTag = pointy.GetPointer("新品")
	}

	*headers = []*types.Header{
		{
			Key:   "x-class",
			Value: "com.djx.appview.MallGoodsPage",
		},
	}

	return &types.GoodsDetailInfo{
		BasicInfo: &types.GoodsInfo{
			Id:          res.Id,
			PreTag:      preTag,
			Title:       res.Title,
			Slug:        res.Slug,
			Excerpt:     res.Excerpt,
			MinPrice:    retailPriceMin,
			ShowStock:   showStock,
			StockUnit:   stockUnit,
			Pic:         mediaUrl,
			BuyNumMax:   buyNumMax,
			BuyNumber:   buyNumber,
			GemPriceMin: pointy.GetPointer(gemPriceMin),
			Skus:        skus,
		},
		HasMoreSelect: hasMoreSelect,
		Categories:    categories,
		Tags:          tags,
		Content:       res.Content,
		Tracing:       res.Tracing,
		Brand:         brand,
		Perfume:       perfume,
		Media:         photos,
		Meta:          meta,
		Attrs:         attrs,
		Specs:         specs,
	}, nil
}
